A compiler translates human-readable source code into machine-readable object code. For example, a compiler may be utilized to translate the source code shown in FIG. 1 into object code. Line 1 of FIG. 1 defines a “main” procedure. The procedure includes instructions located between the forward bracket in line 2 and the reverse bracket on line 11. Line 7 of FIG. 1 contains a label statement that defines “label1.” Similarly, line 9 contains a label statement that defines “label2.” Line 4 of FIG. 1 contains a “goto” statement for commanding a computer to branch to “label1,” i.e., line 7. Similarly, line 5 of the source code contains a goto statement for commanding the computer to branch to “label2” i.e., line 9. Finally, line 10 contains a “printf” statement for commanding a computer to print the phrase “End of program.” Lines 3, 6 and 8 of FIG. 1 contain other source code statements that are not shown.
In addition to generating object code, some compilers, known as optimizing compilers, optimize the object code so that a computer can store and execute the object code more efficiently. For example, an optimizing compiler may increase the efficiency of object code by analyzing program flow. As a result of a program flow analysis, an optimizing compiler could determine that the program flow of the source code in FIG. 1 would always bypass the “goto label2” statement in line 5. Thus, that statement, as well as the “label2” statement in line 9, could be eliminated. As a result, the optimizing compiler could optimize the generated object code to have a structure as shown in FIG. 2. Such object code would be smaller than and would be executed faster than non-optimized object code.
One type of statement utilized in some computer programs is a computed goto statement. Computed goto statements are useful to command a computer to branch to one of several labels based upon program logic. As a result, computed goto statements enable a high degree of branching flexibility. For example, a programmer can use computed goto statements to allow runtime information to determine branching destinations. More specifically, a programmer could store the address of a program label (a branch destination) in a variable and then utilize a computed goto statement to branch to the value stored in the variable. Additional information on computed goto statements can be found at: http://gcc.gnu.org/onlinedocs/gcc-3.2/gcc/Labels-as-Values.html#Labels%20as%20Values.
An example of a computer program using a computed goto statement is shown in FIG. 3. Line 3 of FIG. 3 defines a pointer to variable “ptr.” Line 4 assigns, using the unary operator &&, the address of the label “label3” to “ptr.” FIG. 3 contains a similar statement in line 6 that conditionally assigns the address of the label “label4” to “ptr.” Thus, under some, but not all circumstances, line 6 of FIG. 3 will reassign “ptr.” Line 8 contains a computed goto statement for commanding a computer to branch to the address currently stored within “ptr.” The address to which the computer branches depends upon whether the conditional assignment in line 6 reassigns “ptr.” If “ptr” is reassigned, then the computer branches to line 11. However, if “ptr” is not reassigned, then the computer branches to line 9.
The use of computed goto statements makes some optimizations difficult for a compiler. As a result of the existence of the computed goto statement, a conventional compiler may not be able to optimize object code by eliminating the “goto label2” statement in line 14 and the label “label2” in line 18 of FIG. 3. Thus, a need exists for a compiler that can translate source code that contains computed goto statements into optimized object code.